package edu.geo.spaghetti;

import java.io.Serializable;
import java.util.ArrayList;
import java.util.Collection;
import java.util.HashMap;
import java.util.List;

import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;

import com.vividsolutions.jts.geom.Coordinate;
import com.vividsolutions.jts.operation.polygonize.Polygonizer;

import edu.geo.containers.geom.impl.GeometryFactory;
import edu.geo.containers.geom.impl.LineSegment;
import edu.geo.containers.geom.impl.Point;
import edu.geo.containers.geom.impl.Polygon;
import edu.geo.containers.geomdomain.GeometricDomain;

public class SpaghettiTransformer implements Serializable {

	/**
	 * 
	 */
	private static final long serialVersionUID = -5900847465246179715L;

	static private final Log LOGGER = LogFactory
			.getLog(SpaghettiTransformer.class);

	public static SpaghettiRepresentation asSpaghettiRepresentation(
			GeometricDomain geometricDomain) {
		LOGGER.info("Generando representación spaghetti");
		Polygonizer poly = new Polygonizer();

		HashMap<Coordinate, Integer> mapPoints = buildPoints(geometricDomain
				.getPoints());

		List<String> lineCoordinates = new ArrayList<String>();
		
		List<LineSegment> lineSegments = new ArrayList<LineSegment>();

		for (LineSegment lineSegment : geometricDomain.getLineSegments()) {
			poly.add(lineSegment);
		}
		SpaghettiRepresentation spaghetti = new SpaghettiRepresentation();
		List<Polygon> polygons = new ArrayList<Polygon>();
		@SuppressWarnings("unchecked")
		Collection<com.vividsolutions.jts.geom.Polygon> jtsPolygons = poly
				.getPolygons();
		for (com.vividsolutions.jts.geom.Polygon polygon : jtsPolygons) {
			Polygon pol = GeometryFactory.createPolygon(polygon);
			for (int i = 0; i < pol.getPoints().size(); ++i) {
				Point p1 = pol.getPoints().get(i);
				if (mapPoints.containsKey(p1.getCoordinate())) {
					int id = mapPoints.get(p1.getCoordinate());
					pol.getPoints().get(i).setId(id);
					LOGGER.info(id);
				}
			}
			polygons.add(pol);
			addLineSegments(lineCoordinates, pol);
		}
		// Cargar segmentos de línea que no estén en los polígonos
		for (LineSegment ls : geometricDomain.getLineSegments()) {
			if (!lineCoordinates.contains(ls.toText())) {
				lineSegments.add(ls);
			}
		}
		//Polígonos
		spaghetti.setPolygons(polygons);
		//Líneas
		spaghetti.setLineSegments(lineSegments);
		//Puntos
		spaghetti.setPoints(geometricDomain.getPoints());
		
		
		
		
		return spaghetti;
	}

	private static void addLineSegments(List<String> lineSegments,
			Polygon polygons) {
		List<Point> points = polygons.getPoints();
		for (int i = 0; i < points.size() - 1; ++i) {
			lineSegments.add(GeometryFactory.createLineSegment(points.get(i),
					points.get(i + 1)).toText());
			lineSegments.add(GeometryFactory.createLineSegment(points.get(i+1),
					points.get(i)).toText());
		}
	}

	private static HashMap<Coordinate, Integer> buildPoints(List<Point> points) {
		HashMap<Coordinate, Integer> mapPoints = new HashMap<Coordinate, Integer>();
		for (Point point : points) {
			Coordinate jtsPoint = point.getCoordinate();
			mapPoints.put(jtsPoint, point.getId());
		}
		return mapPoints;
	}
}
